package cn.lonecloud.study;

import cn.lonecloud.study.config.ZkConfig;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

/**
 * @author lonecloud
 * @version v1.0
 * @Package cn.lonecloud.study
 * @Description: TODO
 * @date 2018/5/23下午6:04
 */
public class ZkReentrantLock extends AbstractZkLock{

    private String lockPath;


    private CountDownLatch countDownLatch = null;

    public ZkReentrantLock(ZkConfig zkConfig, String lockPath) throws IOException {
        super(zkConfig);
        this.lockPath = lockPath;
    }

    @Override
    public void lock() {
        while (!tryLock()) {
            try {
                //判断节点是否存在，并添加事件监听
                Stat stat = zooKeeper.exists(lockPath, this);
                //如果其为不为null则表明这个节点已经存在了，则说明其共享资源已经被占用了
                if (stat!=null){
                    //创建节点失败表示没有获取到锁资源
                    countDownLatch = new CountDownLatch(1);
                    //等待
                    countDownLatch.await();
                }
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        this.lock();
    }

    @Override
    public boolean tryLock() {
        try {
            zooKeeper.create(lockPath, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            return true;
        } catch (KeeperException | InterruptedException e) {
            logger.error("can't get lock"+e);
            return false;
        }
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        if (!tryLock()) {
            //创建节点失败表示没有获取到锁资源
            countDownLatch = new CountDownLatch(1);
            try {
                countDownLatch.await(time,unit);
            } catch (InterruptedException e1) {
                logger.error("await error");
            }
            return false;
        }
        return true;
    }

    @Override
    public Condition newCondition() {
        return null;
    }

    @Override
    public void process(WatchedEvent event) {
        Event.EventType type = event.getType();
        //解锁判断节点删除，则说明锁已经释放
        if (Event.EventType.NodeDeleted.equals(type)){
            if (countDownLatch!=null){
                countDownLatch.countDown();
            }
        }
    }
}
